package com.secsbrain.development.biz.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.framework.service.impl.SuperServiceImpl;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.secsbrain.cmdb.client.iface.AppInfoService;
import com.secsbrain.common.ErrorCodeEnum;
import com.secsbrain.common.ResponseResult;
import com.secsbrain.common.ResponseVo;
import com.secsbrain.cmdb.client.model.AppDetail;
import com.secsbrain.common.utils.DateTimeUtils;
import com.secsbrain.common.utils.HttpClientUtil;
import com.secsbrain.development.biz.IBranchService;
import com.secsbrain.development.biz.exception.BranchException;
import com.secsbrain.development.biz.model.BranchMerge;
import com.secsbrain.development.biz.model.BranchParam;
import com.secsbrain.development.biz.model.GitInfo;
import com.secsbrain.development.dal.mapper.BranchActionRecordMapper;
import com.secsbrain.development.dal.mapper.BranchTypeRuleMapper;
import com.secsbrain.development.dal.model.BranchActionRecord;
import com.secsbrain.development.dal.model.BranchTypeRule;

import com.secsbrain.development.biz.constant.EnumDefinition;

import org.apache.commons.httpclient.Header;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class BranchServiceImpl extends SuperServiceImpl<BranchActionRecordMapper, BranchActionRecord> implements IBranchService {

    private static final Logger logger = LoggerFactory.getLogger(BranchServiceImpl.class);

    /**
     * 分支类型规则缓存
     */
    private Map<Long, BranchTypeRule> branchTypeRuleCache = new ConcurrentHashMap<>();

    @Value("${gitlab.token}")
    private String privateToken;//gitlab 私钥

    public static final String MERGE_INFO = "项目管理系统分支合并";

    /**
     * 分隔符
     */
    public static final String SEPARATOR = "_";

    @Autowired
    BranchTypeRuleMapper branchTypeRuleMapper;

    @Autowired
    BranchActionRecordMapper branchActionRecordMapper;

    @Autowired
    AppInfoService appInfoService;

    public void loadData() {
        logger.debug("加载分支类型规则数据开始。。。");

        branchTypeRuleCache.clear();
        EntityWrapper<BranchTypeRule> entityWrapper = new EntityWrapper<BranchTypeRule>(new BranchTypeRule());
		List<BranchTypeRule> list = branchTypeRuleMapper.selectList(entityWrapper);

        for (BranchTypeRule branchTypeRule : list) {
            branchTypeRuleCache.put(branchTypeRule.getId(), branchTypeRule);
        }
    }

    @Override
    public ResponseResult<?> mergeBranch(BranchMerge branchMerge) {
        logger.debug("合并分支开始：{}", branchMerge);

        ResponseResult baseResult = new ResponseResult(false);
        ResponseVo<AppDetail> appResult=appInfoService.queryAppDetailById(branchMerge.getProjectId());
        AppDetail app = appResult.getData();
        if (app == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "没有查询到相应的工程");
        }

        BranchActionRecord param = new BranchActionRecord();
        param.setProjectId(branchMerge.getProjectId());
        param.setBranchName(branchMerge.getBranchName());
        param.setActionType(EnumDefinition.BranchActionType.PULL.getCode());
        BranchActionRecord branchActionRecord = branchActionRecordMapper.selectOne(param);
        if (branchActionRecord == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "没有查询到分支拉取记录");
        }

        Long branchTypeId = branchActionRecord.getBranchTypeId();
        //待合并分支的类型规则
        BranchTypeRule branchTypeRule = branchTypeRuleCache.get(branchTypeId);

        try {
            String branchToIds = branchTypeRule.getBranchToIds();
            if (branchToIds.indexOf(",") == -1) {
                BranchActionRecord recordMergeTo = this.getToBranch(Integer.parseInt(branchToIds), branchActionRecord);
                ((BranchServiceImpl) AopContext.currentProxy()).mergeBranch(app.getGitUrl(), app.getId(), recordMergeTo);

            } else {
                String[] branchToIdArray = branchToIds.split(",");
                for (String branchToId : branchToIdArray) {
                    BranchActionRecord recordMergeTo = this.getToBranch(Integer.parseInt(branchToId), branchActionRecord);
                    ((BranchServiceImpl) AopContext.currentProxy()).mergeBranch(app.getGitUrl(), app.getId(), recordMergeTo);
                }
            }
        } catch (BranchException e) {
            logger.warn("", e);
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "merge失败：" + e.getMessage());
        } catch (IOException e) {
            logger.error("", e);
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), "网络错误");
        }

        return new ResponseResult();
    }

    private BranchActionRecord getToBranch(Integer branchTypeId, BranchActionRecord branchActionRecord) {
        BranchTypeRule toBranchTypeRule = branchTypeRuleCache.get(branchTypeId);
        if (toBranchTypeRule.getSelected() == 0) {
            //要合并的分支，类型规则是不可选，则为trunk或master分支。
            branchActionRecord.setRelateBranch(toBranchTypeRule.getBranchNamePrefix());
            branchActionRecord.setRelateBranchType(toBranchTypeRule.getId());
            return branchActionRecord;
        } else {
            //如果要合并的分支类型跟之前拉的关联分支是一个类型，则合并到那个分支
            if (branchActionRecord.getRelateBranchType().equals(toBranchTypeRule.getId())) {
                return branchActionRecord;
            } else {
                logger.warn("没有找到要合并的分支。。。");
            }
        }
        return null;
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void mergeBranch(String gitUrl, Long projectId, BranchActionRecord branchMerge) throws IOException {
        BranchActionRecord branchActionRecord = new BranchActionRecord();
        branchActionRecord.setActionType(EnumDefinition.BranchActionType.MERGE.getCode());
        branchActionRecord.setBranchTypeId(branchMerge.getRelateBranchType());
        branchActionRecord.setBranchName(branchMerge.getRelateBranch());
        branchActionRecord.setCreateTime(new Date());
        branchActionRecord.setProjectId(projectId);
        branchActionRecord.setRelateBranch(branchMerge.getBranchName());
        branchActionRecord.setRelateBranchType(branchMerge.getBranchTypeId());
        branchActionRecordMapper.insertSelective(branchActionRecord);

        GitInfo gitInfo = this.getGitInfo(gitUrl);
        String mergeRequestUrl = gitInfo.getUrl() + "/projects/" + gitInfo.getId() + "/merge_requests";

        Header header = new Header("PRIVATE-TOKEN", privateToken);
        Header[] headers = {header};

        Map<String, String> params = new HashMap<>();
        params.put("source_branch", branchMerge.getBranchName());
        params.put("target_branch", branchMerge.getRelateBranch());
        params.put("title", MERGE_INFO + "from " + branchMerge.getBranchName() + "to " + branchMerge.getRelateBranch());

        String mergeRequestJson = HttpClientUtil.submitPostWithHeader(mergeRequestUrl,params,headers);
        logger.debug("mergeRequest结果：{}", mergeRequestJson);

        Map<?, ?> mergeRequestMap = JSON.parseObject(mergeRequestJson, Map.class);
        if (!mergeRequestMap.containsKey("id")) {
            if (mergeRequestMap.containsKey("message")) {
                JSONArray jsonArray = (JSONArray) mergeRequestMap.get("message");
                throw new BranchException(jsonArray.toJSONString());
            } else {
                throw new BranchException("request失败");
            }
        }

        Integer mergeRequestId = (Integer) mergeRequestMap.get("id");

        String amcUrl = gitInfo.getUrl() + "/projects/" + gitInfo.getId() + "/merge_requests/" + mergeRequestId + "/merge";

        String resJson = HttpClientUtil.putRequestWithHeader(amcUrl,"{}",headers);
        logger.debug("accept mc结果：{}", resJson);

        Map<?, ?> map = JSON.parseObject(resJson, Map.class);
        if (!map.containsKey("id")) {
            if (map.containsKey("message")) {
                throw new BranchException((String) map.get("message"));
            } else {
                throw new BranchException("accept mc失败");
            }
        }
    }

    @Override
    public ResponseResult<String> createBranch(BranchParam branchParam) {
        logger.debug("创建分支开始......参数：{}", branchParam);

        if (branchParam.getProjectId() == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "工程ID不能为空");
        }

        ResponseVo<AppDetail> appResult=appInfoService.queryAppDetailById(branchParam.getProjectId());
        AppDetail app = appResult.getData();
        if (app == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "没有查询到相应的工程");
        }

        if (branchParam.getBranchTypeId() == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "分支类型ID不能为空");
        }

        BranchTypeRule branchTypeRule = branchTypeRuleCache.get(branchParam.getBranchTypeId());
        if (branchTypeRule == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "没有查询到相应分支类型");
        }

        if (branchTypeRule.getSelected() == 0) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), branchTypeRule.getBranchTypeName() + "不能被创建！");
        }

        Long sourceBranchTypeId = this.getSourceBranchTypeId(branchParam.getSourceBranch(), branchParam.getProjectId());
        if (sourceBranchTypeId == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "分支来源名称不正确");
        }

        String branchName = "";
        if (StringUtils.isNotEmpty(branchParam.getBranchName())) {
            branchName = branchParam.getBranchName();
        } else {
            try {
                branchName = this.generateBranchName(branchTypeRule, branchParam);
            } catch (ParseException e) {
                logger.error("", e);
                return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), "时间格式化错误");
            }
        }

        logger.debug("分支名称：{}", branchName);

        try {
            ((BranchServiceImpl) AopContext.currentProxy()).createGitBranch(app.getGitUrl(), branchParam.getProjectId(), branchParam.getBranchTypeId(),
                    branchName, sourceBranchTypeId, branchParam.getSourceBranch());
        } catch (IOException e) {
            logger.error("", e);
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), "网络错误");
        } catch (BranchException e) {
            logger.warn("", e);
            logger.error("", e);
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), "分支创建失败：" + e.getMessage());
        }

        return new ResponseResult<>(branchName);//返回分支名
    }

    public Long getSourceBranchTypeId(String sourceBranch, Long projectId) {
        if (StringUtils.isEmpty(sourceBranch)) {
            return null;
        }

        BranchTypeRule branchTypeRuleParam = new BranchTypeRule();
        branchTypeRuleParam.setBranchNamePrefix(sourceBranch);
        branchTypeRuleParam.setSelected(0);
        EntityWrapper<BranchTypeRule> entityWrapper=new EntityWrapper<BranchTypeRule>(branchTypeRuleParam);
		List<BranchTypeRule> branchTypeRules = branchTypeRuleMapper.selectList(entityWrapper);
        if (CollectionUtils.isEmpty(branchTypeRules)) {
            if (projectId == null) {
                return null;
            }

            BranchActionRecord branchActionRecordParam = new BranchActionRecord();
            branchActionRecordParam.setProjectId(projectId);
            branchActionRecordParam.setBranchName(sourceBranch);
            List<BranchActionRecord> branchActionRecords = this.selectList(branchActionRecordParam);
            if (CollectionUtils.isEmpty(branchActionRecords)) {
                return null;
            }
            return branchActionRecords.get(0).getBranchTypeId();
        }

        return branchTypeRules.get(0).getId();
    }

    /**
     * 功能描述: <br>
     * 生成分支名称
     *
     * @param branchTypeRule 分支类型规则
     * @param branchParam    分支参数
     * @return
     * @throws ParseException
     */
    private String generateBranchName(BranchTypeRule branchTypeRule, BranchParam branchParam) throws ParseException {
        StringBuilder branchNameBuilder = new StringBuilder();
        branchNameBuilder.append(branchTypeRule.getBranchNamePrefix());
        String branchNameDateformat = branchTypeRule.getBranchNameDateformat();
        if (StringUtils.isNotEmpty(branchTypeRule.getBranchNameDateformat())) {
            branchNameBuilder.append(SEPARATOR);
            if (branchTypeRule.getNowdate() == 0) {
                branchNameBuilder.append(DateTimeUtils.parseDateAsString(new Date(), branchNameDateformat));
            } else {
                //指定日期
                branchNameBuilder.append(DateTimeUtils.parseDateAsString(
                        DateTimeUtils.parseStringAsDate(branchParam.getTargetDate(), "yyyy-MM-dd"), branchNameDateformat));
            }
        }

        if (branchTypeRule.getUserNameRadom() == 1) {
            branchNameBuilder.append(SEPARATOR);
            branchNameBuilder.append(branchParam.getUserName());

            //如果名称已经存在，则在后面加1
            int i = 0;
            while (true) {
                String index = "";
                if (i > 0) {
                    index = String.valueOf(i);
                }
                BranchActionRecord branchActionRecordParam = new BranchActionRecord();
                branchActionRecordParam.setProjectId(branchParam.getProjectId());
                branchActionRecordParam.setBranchName(branchNameBuilder.toString() + index);
                branchActionRecordParam.setActionType(EnumDefinition.BranchActionType.PULL.getCode());
                List<BranchActionRecord> branchActionRecords = this.selectList(branchActionRecordParam);
                if (CollectionUtils.isEmpty(branchActionRecords)) {
                    return branchNameBuilder.toString() + index;
                }

                i++;
            }

        }
        return branchNameBuilder.toString();
    }

    /**
     * 功能描述: <br>
     * 获取gitlab api所需信息
     *
     * @param gitUrl
     * @return
     * @throws IOException
     */
    private GitInfo getGitInfo(String gitUrl) throws IOException {
        URL url = new URL(gitUrl);

        GitInfo gitInfo = new GitInfo();
        gitInfo.setUrl(url.getProtocol() + "://" + url.getHost() + "/api/v3");
        gitInfo.setId(URLEncoder.encode(url.getPath().substring(1, url.getPath().indexOf(".git")), "UTF-8"));
        return gitInfo;
    }

    /**
     * 功能描述: <br>
     * 创建git分支
     *
     * @param gitUrl             git路径
     * @param projectId          工程ID
     * @param branchTypeId       分支类型ID
     * @param branchName         分支名称
     * @param sourceBranchTypeId 来源分支类型ID
     * @param sourceBranch       来源分支
     * @throws IOException
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void createGitBranch(String gitUrl, Long projectId,
    		Long branchTypeId, String branchName, Long sourceBranchTypeId, String sourceBranch) throws IOException {
        BranchActionRecord branchActionRecord = new BranchActionRecord();
        branchActionRecord.setActionType(EnumDefinition.BranchActionType.PULL.getCode());
        branchActionRecord.setBranchTypeId(branchTypeId);
        branchActionRecord.setBranchName(branchName);
        branchActionRecord.setCreateTime(new Date());
        branchActionRecord.setProjectId(projectId);
        branchActionRecord.setRelateBranch(sourceBranch);
        branchActionRecord.setRelateBranchType(sourceBranchTypeId);
        branchActionRecordMapper.insertSelective(branchActionRecord);

        GitInfo gitInfo = this.getGitInfo(gitUrl);

        String makeBranchUrl = gitInfo.getUrl() + "/projects/" + gitInfo.getId() + "/repository/branches";

        Header header = new Header("PRIVATE-TOKEN", privateToken);
        Header[] headers = {header};

        Map<String, String> params = new HashMap<>();
        params.put("branch_name", branchName);
        params.put("ref", sourceBranch);

        String resJson = HttpClientUtil.submitPostWithHeader(makeBranchUrl,params,headers);
        logger.debug("创建分支结果：{}", resJson);

        Map<?, ?> map = JSON.parseObject(resJson, Map.class);
        if (!map.containsKey("name")) {
            if (map.containsKey("message")) {
                throw new BranchException((String) map.get("message"));
            } else {
                throw new BranchException("创建git分支失败");
            }
        }

    }

    @Override
    public ResponseResult<List<BranchTypeRule>> queryBranchTypeRule() {
        try {
            EntityWrapper<BranchTypeRule> entityWrapper = new EntityWrapper<BranchTypeRule>(new BranchTypeRule());
            List<BranchTypeRule> list = branchTypeRuleMapper.selectList(entityWrapper);

            Map<Long, String> idNameMap = new HashMap<>();
            for (BranchTypeRule branchTypeRule : list) {
                idNameMap.put(branchTypeRule.getId(), branchTypeRule.getBranchTypeName());
            }

            for (BranchTypeRule branchTypeRule : list) {
                String fromIds = branchTypeRule.getBranchFromIds();
                String[] fromIdArray = fromIds.split(",");
                String formatfromIdStr = "";
                if (fromIdArray.length > 0) {
                    for (String str : fromIdArray) {
                        formatfromIdStr += idNameMap.get(Integer.parseInt(str)) + ",";
                    }
                    formatfromIdStr = formatfromIdStr.substring(0, formatfromIdStr.length() - 1);
                } else {
                    formatfromIdStr = idNameMap.get(Integer.parseInt(fromIds));
                }
                branchTypeRule.setBranchFromIds(formatfromIdStr);

                String toIds = branchTypeRule.getBranchToIds();
                String[] toIdArray = toIds.split(",");
                String formattoIdStr = "";
                if (toIdArray.length > 0) {
                    for (String str : toIdArray) {
                        formattoIdStr += idNameMap.get(Integer.parseInt(str)) + ",";
                    }
                    formattoIdStr = formattoIdStr.substring(0, formattoIdStr.length() - 1);
                } else {
                    formattoIdStr = idNameMap.get(Integer.parseInt(fromIds));
                }
                branchTypeRule.setBranchToIds(formattoIdStr);
            }

            return new ResponseResult<>(list);
        } catch (Exception e) {
            logger.error("", e);
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), "网络错误");
        }
    }

    @Override
    public ResponseResult<Page<BranchActionRecord>> queryBranchList(Integer start, Integer limit, BranchActionRecord branchActionRecord) {
        try {
            Page<BranchActionRecord> pageList=new Page<>(start,limit);
            int count = branchActionRecordMapper.selectCount(branchActionRecord);
            pageList.setTotal(count);

            EntityWrapper<BranchActionRecord> entityWrapper=new EntityWrapper<>(branchActionRecord, "create_time desc");
            List<BranchActionRecord> list = branchActionRecordMapper.selectPage(new RowBounds(start, limit), entityWrapper);

            for (BranchActionRecord actionRecord : list) {
                actionRecord.setFormatTime(DateTimeUtils.parseDateAsString(actionRecord.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
                actionRecord.setBranchTypeName(branchTypeRuleCache.get(actionRecord.getBranchTypeId()).getBranchTypeName());
                actionRecord.setRelateBranchTypeName(branchTypeRuleCache.get(actionRecord.getRelateBranchType()).getBranchTypeName());
                //TODO 此处遍历查询要改
                ResponseVo<AppDetail> appResult=appInfoService.queryAppDetailById(actionRecord.getProjectId());
                AppDetail app = appResult.getData();
                actionRecord.setProjectName(app.getName());
            }

            pageList.setRecords(list);

            return new ResponseResult<>(pageList);

        } catch (Exception e) {
            logger.error("", e);
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(), "网络错误");
        }
    }

    @Override
    public Map<Long, BranchTypeRule> getBranchTypeCache() {
        return branchTypeRuleCache;
    }

}
